package com.irain.pp.account.service.mgmt.impl;

import com.irain.pp.account.repository.enums.AccountType;
import com.irain.pp.account.repository.enums.UserRecordType;
import com.irain.pp.account.repository.model.PpUserRecordDO;
import com.irain.pp.tool.BizAssert;
import com.irain.pp.tool.JavaBeanUtils;
import com.irain.pp.tool.annotation.NotNull;
import com.irain.pp.tool.mybatis.mapper.PpRecordMapper;
import com.irain.pp.tool.mybatis.mgmt.BaseCacheManagerImpl;
import com.irain.pp.account.repository.model.PpUserDO;
import com.irain.pp.account.service.mgmt.PpUserManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

/**
 * @author WangYanPeng
 * @date 2017/10/17 20:00
 */
@Component
public class PpUserManagerImpl extends BaseCacheManagerImpl<PpUserDO> implements PpUserManager {

    @Autowired
    private PpRecordMapper<PpUserRecordDO> recordMapper;

    @Override
    public PpUserDO get(@NotNull AccountType accountType, @NotNull String accountValue){
        Long id = getIdByCache(accountType.name(), new Object[]{accountValue}, () -> {
            PpUserDO condition = new PpUserDO();
            accountType.setFiled(condition,accountValue);
            return selectOne(condition);
        });
        return selectById(id);
    }

    @NotNull
    @Override
    @Transactional
    public PpUserDO create(@NotNull AccountType accountType, @NotNull String accountValue, String passwordHash) {
        PpUserDO ppUserDO = new PpUserDO();
        ppUserDO.setAccountType(accountType);
        accountType.setFiled(ppUserDO, accountValue);
        ppUserDO.setPasswordHash(passwordHash);
        insert(ppUserDO);
        insertUserRecord(UserRecordType.CREATE, ppUserDO);
        return ppUserDO;
    }

    @NotNull
    @Override
    @Transactional
    public PpUserDO replayPassword(@NotNull Long id, @NotNull String passwordHash) {
        PpUserDO updateParams = new PpUserDO();
        updateParams.setPasswordHash(passwordHash);
        Example example = initExample();
        example.and().andIsNotNull(PpUserDO.PASSWORD_HASH);
        updateOneByExampleSelective(id,updateParams, example);
        PpUserDO ppUserDO = selectById(id);
        insertUserRecord(UserRecordType.REPLAY_PASSWORD, ppUserDO);
        return ppUserDO;
    }

    /*---------------- index userName ------------------*/


    @NotNull
    @Override
    @Transactional
    public PpUserDO perfectUserName(@NotNull Long id, @NotNull String userName, String passwordHash) {
        PpUserDO updateParams = new PpUserDO();
        updateParams.setAccountType(AccountType.USER_NAME);
        updateParams.setUserName(userName);
        updateParams.setPasswordHash(passwordHash);
        Example example = initExample();
        Example.Criteria criteria = example.and();
        criteria.andNotEqualTo(PpUserDO.ACCOUNT_TYPE, AccountType.USER_NAME);
        if (passwordHash == null) {
            criteria.andIsNotNull(PpUserDO.PASSWORD_HASH);
        } else {
            criteria.andIsNull(PpUserDO.PASSWORD_HASH);
        }
        updateOneByExampleSelective(id,updateParams, example);
        PpUserDO ppUserDO = selectById(id);
        insertUserRecord(UserRecordType.PERFECT_ACCOUNT, ppUserDO);
        return ppUserDO;
    }

    /*----------------- end userName ------------------*/


    /*---------------- index mobile -------------------*/

    @NotNull
    @Override
    @Transactional
    public PpUserDO bindMobile(@NotNull Long id, @NotNull String mobile) {
        PpUserDO updateParams = new PpUserDO();
        updateParams.setMobile(mobile);
        PpUserDO condition = new PpUserDO();
        condition.setAccountType(AccountType.USER_NAME);
        Example example = initExample(condition);
        example.and().andIsNull(PpUserDO.MOBILE);
        updateOneByExampleSelective(id,updateParams, example);
        PpUserDO ppUserDO = selectById(id);
        insertUserRecord(UserRecordType.BIND_MOBILE, ppUserDO);
        saveIdByCache(PpUserDO.MOBILE, new Object[]{mobile}, id);
        return ppUserDO;
    }

    @NotNull
    @Override
    @Transactional
    public PpUserDO unbindMobile(@NotNull Long id, @NotNull String mobile) {
        PpUserDO ppUserDO = selectByIdForUpdate(id);
        BizAssert.notEqual(ppUserDO.getAccountType(),AccountType.USER_NAME, "请先完善帐户信息");
        BizAssert.isEqual(ppUserDO.getMobile(), mobile, "解绑手机号不一致");
        ppUserDO.setMobile(null);
        updateById(ppUserDO);
        insertUserRecord(UserRecordType.UNBIND_MOBILE, ppUserDO);
        deleteIdByCache(PpUserDO.MOBILE, new Object[]{mobile});
        return ppUserDO;
    }

    @NotNull
    @Override
    @Transactional
    public PpUserDO replaceMobile(@NotNull Long id, @NotNull String oldMobile, @NotNull String newMobile) {
        BizAssert.notEqual(oldMobile, newMobile, "换绑的新手机号与旧手机号相同");
        PpUserDO updateParams = new PpUserDO();
        updateParams.setMobile(newMobile);
        PpUserDO condition = new PpUserDO();
        condition.setMobile(oldMobile);
        condition.setAccountType(AccountType.USER_NAME);
        Example example = initExample(condition);
        updateOneByExampleSelective(id,updateParams, example);
        PpUserDO ppUserDO = selectById(id);
        insertUserRecord(UserRecordType.REPLAY_MOBILE, ppUserDO);
        saveIdByCache(PpUserDO.MOBILE, new Object[]{newMobile}, id);
        deleteIdByCache(PpUserDO.MOBILE, new Object[]{oldMobile});
        return ppUserDO;
    }

    /*-------------- end mobile ---------------*/

    /*------------- index common --------------*/


    private void insertUserRecord(UserRecordType recordType, PpUserDO ppUserDO) {
        PpUserRecordDO recordDO = new PpUserRecordDO();
        recordDO.setRecordType(recordType);
        recordDO.setUserId(ppUserDO.getId());
        recordDO.setSnapshot(JavaBeanUtils.toJsonString(ppUserDO));
        insertRecord(recordMapper, recordDO);
    }

}